package com.lingtianyu.tech.erbaoshen.core.consumer.bean;

import com.lingtianyu.tech.erbaoshen.core.config.ErBaoShenRpcApplicationContextAware;
import com.lingtianyu.tech.erbaoshen.core.consumer.bean.annotation.ReferenceParamType;
import com.lingtianyu.tech.erbaoshen.core.consumer.bean.annotation.Reference;
import com.lingtianyu.tech.erbaoshen.core.consumer.service.GenericService;
import com.lingtianyu.tech.erbaoshen.core.context.ErBaoShenRpcResultContext;
import com.lingtianyu.tech.erbaoshen.core.util.ErBaoShenFinals;
import io.vavr.Tuple2;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class ReferenceBeanProxy implements InvocationHandler {

    private String interfaceName;
    private Class<?> interfaceClass;
    private String group;
    private String version;

    public ReferenceBeanProxy(Reference reference, Class<?> type) {
        if (reference != null) {
            this.interfaceName = reference.interfaceName();
            this.interfaceClass = reference.interfaceClass();
            this.group = reference.group();
            this.version = reference.version();
        }
        if (this.interfaceClass == null || this.interfaceClass == void.class) {
            this.interfaceClass = type;
        }
    }

    public ReferenceBeanProxy(String interfaceName, Class<?> interfaceClass, String group, String version) {
        this.interfaceName = interfaceName;
        this.interfaceClass = interfaceClass;
        this.group = group;
        this.version = version;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        GenericService genericService = (GenericService) ErBaoShenRpcApplicationContextAware.getApplicationContext().getBean("erBaoShenGenericService");
        if (interfaceName == null || interfaceName.isEmpty()) {
            interfaceName = interfaceClass.getTypeName();
        }
        Parameter[] parameters = method.getParameters();
        List<String> paramTypes = Collections.emptyList();
        if (parameters != null && parameters.length > 0) {
            paramTypes = new ArrayList<>(parameters.length);
            for (Parameter parameter : parameters) {
                ReferenceParamType annotation = parameter.getAnnotation(ReferenceParamType.class);
                if (annotation != null) {
                    String value = annotation.value();
                    if (!value.isEmpty()) {
                        paramTypes.add(value);
                        continue;
                    }
                }
                paramTypes.add(parameter.getType().getTypeName());
            }
        }
        List<Object> params = Collections.emptyList();
        if (args != null && args.length > 0) {
            params = new ArrayList<>(args.length);
            for (Object arg : args) {
                params.add(arg);
            }
        }
        ErBaoShenRpcResultContext.clear();
        Tuple2<Object, Map<String, List<String>>> t2 = genericService.runMethod(interfaceName, group, version, method.getName(), paramTypes, params, method.getGenericReturnType());
        ErBaoShenRpcResultContext.setAttachment(ErBaoShenFinals.RESULT_CONTEXT_HEADER_KEY, t2._2);
        return t2._1;
    }
}
